//
// Created on 2025/1/20.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef CANVASTEST_TESTING_H
#define CANVASTEST_TESTING_H

#include <map>
#include <list>
#include <unordered_map>
#include <native_drawing/drawing_types.h>
#include "core/SkCanvas.h"

#define DEFAULT_DRAWING_HEIGHT 300

#define TESTING_EXPORT __attribute__((visibility("default")))

typedef void (*Test_Canvas_Fun)(SkCanvas &test_canvas);

typedef struct Test_Case {
    int caseHeight = 0;
    Test_Canvas_Fun caseFun;
    sk_sp<SkPicture> casePicture;
    sk_sp<SkPicture> casePictureC;
    SkPictureRecorder *caseRecorder = nullptr;
    SkPictureRecorder *caseRecorderC = nullptr;
    int picNum = 0;
    std::string caseName = "";
} Test_Case;


enum TEST_LEVEL {
    NORMAL = 0,
    /**
     * SELF_TESTING is used for local testing.
     */
    SELF_TESTING,
    NONE,
};

class TestRegistry {
public:
    static TestRegistry &GetInstance() {
        static TestRegistry instance;
        return instance;
    }
    void registerTestCase(const char *name, Test_Canvas_Fun fun, TEST_LEVEL level, int height);
    std::list<Test_Case> &getTestingCaseList();

private:
    std::list<Test_Case> fAllNormalTestingCases;
    std::list<Test_Case> fAllSelfTestingCases;
//    std::map<std::string, int> fAllTestingCaseHeight;
};

class TESTING_EXPORT Testing {
public:
    static Testing &GetInstance() {
        static Testing testing;
        return testing;
    };
    void setDrawCanvas(OH_Drawing_Canvas *canvas, int width, int height);
    void touchPointMove(int touchType, int x, int y, int id);
    void startTesting(SkCanvas *canvas = nullptr, bool isCAPI = false);
    void destroyAllTestCasePictures();
    
    void addPixelmapData(OH_PixelmapNative *pixelmap);
    int getPixelmapNum();
    OH_PixelmapNative *getPixelmapData(int index);
    
    void addExternalNode(std::shared_ptr<OHRenderNode> node);
    int getNodeNum();
    std::shared_ptr<OHRenderNode> getExternalNode(int index);
    void destroyExternalNode();
    

    void addGifData(void* data, size_t length);
    int getGifNum();
    void* getGifData(size_t *length, int index);
    void addPicData(void* data, size_t length);
    int getPicNum();
    void* getPicData(size_t *length, int index);
    void setFontPath(char *path) {
        fFontPath = std::string(path);
    }
    std::string getFontPath() {
        return fFontPath;
    }
    static void buildTestCasePicture(Test_Case& test);
    static bool gCAPI;

private:
    void runTestCases(std::list<Test_Case> &test_cases);
    
    std::vector<std::pair<void*, size_t>> picDatas;
    std::vector<std::pair<void*, size_t>> gifDatas;
    std::vector<OH_PixelmapNative *> pixelmapDatas;

    std::vector<std::shared_ptr<OHRenderNode>> externalNodes;

    OH_Drawing_Canvas *fOHCanvas = nullptr;
    SkCanvas *fCanvas = nullptr;
    int fWindowWidth = 0;
    int fWindowHeight = 0;

    typedef struct Position {
        int x;
        int y;
    } Position;
    bool fTouchFlag[10] = {};
    Position fTouchPosition[10] = {};
//    SkMatrix fCanvasMatrix = SkMatrix::Scale(0.1, 0.1).postTranslate(200, 0);
    SkMatrix fCanvasMatrix = SkMatrix();
    bool matrixInit = false;
    int fLastCenterX = 0, fLastCenterY = 0;
    float fLastDistance = 0.f;
    std::string fFontPath;
};

extern int gTesingCnt;

#define REGISTER_TEST(name, fun, level, height)                                                                        \
    namespace {                                                                                                                  \
        const bool _registered_##name = []() {                                                                         \
            TestRegistry::GetInstance().registerTestCase(#name, fun, level, height);                                   \
            return true;                                                                                               \
        }();                                                                                                           \
    }


#define DEF_TEST_CANVAS(name, level)                                                                                   \
    static void TestCanvas_##name(SkCanvas &test_canvas);                                                              \
    REGISTER_TEST(name, TestCanvas_##name, level, DEFAULT_DRAWING_HEIGHT);             \
    void TestCanvas_##name(SkCanvas &test_canvas)

#define DEF_TEST_CANVAS_WITH_HEIGHT(name, level, height)                                                               \
    static void TestCanvas_##name(SkCanvas &test_canvas);                                                              \
    REGISTER_TEST(name, TestCanvas_##name, level, height);                             \
    void TestCanvas_##name(SkCanvas &test_canvas)


#endif // CANVASTEST_TESTING_H
